package com.caishi.lkx.exam.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.common.AdminBaseApi;
import com.caishi.lkx.common.context.RequireContext;
import com.caishi.lkx.common.ienum.ClientType;
import com.caishi.lkx.common.role.Role;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.course.mapper.VideoInfoMapper;
import com.caishi.lkx.course.model.VideoInfoModel;
import com.caishi.lkx.exam.ienum.type.ColumnPosition;
import com.caishi.lkx.exam.model.CategoryModel;
import com.caishi.lkx.exam.model.ChapterModel;
import com.caishi.lkx.exam.model.ColumnModel;
import com.caishi.lkx.exam.model.PaperModel;
import com.caishi.lkx.exam.service.*;
import com.caishi.lkx.exam.vo.ConfigVo;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.impl.BaseEntity;
import com.zzw.common.exception.BizException;

import com.caishi.lkx.exam.dto.ColumnAllDto;
import com.caishi.lkx.exam.ienum.type.ColumnType;
import com.caishi.lkx.exam.ienum.type.PaperType;

import com.caishi.lkx.exam.model.re.ExColumnConfigReModel;
import com.caishi.lkx.exam.records.RecordsCollectType;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutionException;


@Tag(name = "栏目相关接口")
@Slf4j
@RestController
@RequestMapping("/exam/column")
public class ColumnApi extends AdminBaseApi<IColumnService, ColumnModel, String> {

    @Resource
    private IColumnService service;

    @Resource
    private IExColumnConfigReService reService;

    @Resource
    private ICategoryService categoryService;


    @Resource
    private IChapterService chapterService;

    @Resource
    private IPaperRecordsService paperRecordsService;
    @Resource
    private IPaperService paperService;

    @Resource
    private IExColumnConfigReService columnConfigReService;
    @Resource
    private VideoInfoMapper videoInfoMapper;


    @Override
    public IColumnService loadService() {
        return service;
    }

    @Override
    @Roles
    public List<ColumnModel> list(@RequestParam(defaultValue = "10") Integer size, @ModelAttribute ColumnModel model, @NotNull JSONObject otherParam) {
        return super.list(size, model, otherParam);
    }
    @GetMapping("/page-admin")
    @RequireContext({com.caishi.lkx.common.context.Role.CHANNEL})
    public IPage<ColumnModel> page(@ModelAttribute Page<ColumnModel> page, @ModelAttribute ColumnModel model, @NotNull JSONObject otherParam) {
        var groupId = context.getGroupId();
        if(groupId != null && groupId >0L){
            model.setGroupId(groupId);
        }


        IPage<ColumnModel> data = loadService().page(loadService().pageProcessing(page), baseWrapper(model, otherParam));

        data.setRecords(listCover(data.getRecords(), otherParam));
        return data;
    }
    @Override
    protected LambdaQueryWrapper<ColumnModel> baseWrapper(ColumnModel model, JSONObject otherParam) {
        String searchKey = otherParam.getStr("searchKey");
        return super.baseWrapper(model, otherParam).like(StrUtil.isNotBlank(searchKey), ColumnModel::getName, searchKey);
    }

    @Override
    protected List<ColumnModel> listCover(List<ColumnModel> result, JSONObject otherParam) {
        boolean haveCategoryName = otherParam.getBool("haveCategoryName", false);
        boolean haveDataCount = otherParam.getBool("haveDataCount", false);
        if (haveCategoryName) {
            result.parallelStream().forEach(r -> {
                if (null != r.getCategoryId()) {
                    r.setCategoryName(categoryService.queryName(r.getCategoryId()));
                }
                if (haveDataCount) {
                    r.setDataCount(columnConfigReService.selectCount(columnConfigReService.wrappers()
                            .eq(ExColumnConfigReModel::getColumnId, r.getId())
                    ).intValue());
                }
            });
        }
        return super.listCover(result, otherParam);
    }

    @Override
    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    @Roles(Role.admin)
    @RequireContext({com.caishi.lkx.common.context.Role.CHANNEL})
    public ColumnModel add(@RequestBody ColumnModel entity) {
        entity.setGroupId(context.getGroupId());
        ColumnModel columnModel = service.insert(entity);
        operateColumRe(columnModel);
        return columnModel;
    }

    @Override
    @PutMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    @Roles(Role.admin)
    public ColumnModel update(@RequestBody ColumnModel entity) {
        ColumnModel columnModel = service.update(entity);
        operateColumRe(columnModel);
        return columnModel;
    }
    @PostMapping("/update-all")
    @Transactional(rollbackFor = Exception.class)
    @Roles(Role.admin)
    @RequireContext({com.caishi.lkx.common.context.Role.CHANNEL})
    public ColumnModel addColumnAllDto(@RequestBody ColumnAllDto entity) {
        var groupId = context.getGroupId();
        if(groupId != null && groupId >0L){
            entity.setGroupId(groupId);
        }

        ColumnModel columnModel = service.insert(entity);
        operateColumRe(columnModel);
//        if(entity.getType().equals(ColumnType.paperLibrary)){
//            ColumnModel morePaper = this.loadService().morePaperByCategory(entity.getCategoryId());
//            morePaper.setConfigs(entity.getMoreConfigIds());
//            operateColumRe(morePaper);
//        }
        return columnModel;
    }

    @PutMapping("/update-all")
    @Transactional(rollbackFor = Exception.class)
    @Roles(Role.admin)
    public ColumnModel updateColumnAllDto(@RequestBody ColumnAllDto entity) {
        ColumnModel columnModel = service.update(entity);
        operateColumRe(columnModel);
        if(entity.getType().equals(ColumnType.paperLibrary)){
            ColumnModel morePaper = this.loadService().morePaperByCategory(entity.getCategoryId());
            morePaper.setConfigs(entity.getMoreConfigIds());
            operateColumRe(morePaper);
        }
        return columnModel;
    }

    @Operation(summary = "获取集合的所属栏目")
    @GetMapping("/collect-get-column")
    public String collectGetColumnId(@RequestParam Long categoryId, RecordsCollectType recordsType, String id) {
        var all = service.queryCategoryColumns(categoryId);
        if (recordsType == RecordsCollectType.chapter) {
            var ids = chapterService.allParentIds(id);
            ids.add(id);
            return reService.selectFirst(reService.wrappers()
                    .in(ExColumnConfigReModel::getColumnId, all.stream().map(BaseEntity::getId).toList())
                    .in(ExColumnConfigReModel::getConfigId, ids)).getColumnId();
        }
        if (recordsType == RecordsCollectType.paperRecordPaperLibrary || recordsType == RecordsCollectType.paperRecordChapterPractice) {
            var paper = paperRecordsService.getById(id);
            return reService.selectFirst(reService.wrappers()
                    .in(ExColumnConfigReModel::getColumnId, all.stream().map(BaseEntity::getId).toList())
                    .eq(ExColumnConfigReModel::getConfigId, paper.getPaperId())).getColumnId();
        }
        if (recordsType == RecordsCollectType.paperRecordSpecialPractice) {
            return all.stream().filter(v -> v.getType() == ColumnType.specialPractice).findFirst().orElse(new ColumnModel()).getId();
        }
        if (recordsType == RecordsCollectType.paperRecordRandomFormPaper) {
            return all.stream().filter(v -> v.getType() == ColumnType.randomFormPaper).findFirst().orElse(new ColumnModel()).getId();
        }
        return null;
    }

    @GetMapping("/column-by-category")
    @Operation(summary = "根据科目拉取栏目 并判断用户/机构是否有其权限,不登录也可")
    @Parameters({
            @Parameter(name = "categoryId", description = "科目)"),
            @Parameter(name = "columnPosition", description = "栏目位置(MSJX(名师精选),JGQY(金刚区))"),
            @Parameter(name = "type", description = "不传0 ,题库1，资料2，录播3，直播4"),
    })
    @Roles
    @RequireContext(com.caishi.lkx.common.context.Role.APP)
    public List<ColumnModel> getIndustryAndExam(@RequestParam Long categoryId,@RequestParam(required = false) ColumnPosition columnPosition,@RequestParam(required = false) String type) throws ExecutionException, InterruptedException {
//        Long localGroupId = userContext.currentLocalGroupId();
//        Long userGroupId = userContext.currentGroupId();
       var userId = userContext.currentUserId();
//        var ct = userContext.currentTokenData().getClientType();
//        var listFuture = SysThreadPool.submit(() -> {
//            try {
//                return categoryService.currentHaveAuth(userGroupId, localGroupId, userId, categoryId, ct);
//            }catch (BizException e) {
//                return false;
//            }
//        });
        var groupId = context.getGroupId();
        //有权限的栏目ids
        List<ColumnModel> columnModels = getColumnModels(categoryId, groupId, columnPosition,true,type);
        if(columnModels.isEmpty()){
            columnModels = getColumnModels(categoryId, groupId, columnPosition,false,type);
        }
         //var result = listFuture.get();
        columnModels.forEach(column -> {
            try {
                column.setSoldFlag(loadService().currentHaveAuth(null, null, userId, null, column.getId(), ClientType.zyksApp));
            } catch (BizException e) {
                throw new RuntimeException(e);
            }
        });
        return columnModels;
    }

    List<ColumnModel> getColumnModels(Long categoryId, Long groupId, ColumnPosition columnPosition,boolean addGroupId,String type){
     if(StrUtil.isNotBlank(type)){
         return loadService().selectList(Wrappers.<ColumnModel>lambdaQuery()
                 .eq(ColumnModel::getCategoryId, categoryId)
                 .isNull(!addGroupId,ColumnModel::getGroupId)
                 .eq(addGroupId,ColumnModel::getGroupId,groupId)
                 //.eq( ColumnModel::getPosition, columnPosition)
                 .eq(ColumnModel::getShow, true)
                         .in(type.equals("1"),ColumnModel::getType, Arrays.asList(ColumnType.chapterPractice, ColumnType.paperLibrary, ColumnType.specialPractice, ColumnType.randomFormPaper))
                         .eq(type.equals("2"),ColumnModel::getType, ColumnType.materialInfo)
                         .eq(type.equals("3"),ColumnModel::getType, ColumnType.video)
                         .eq(type.equals("4"),ColumnModel::getType, ColumnType.live)
                 .orderByAsc(ColumnModel::getSort));
     }
      return loadService().selectList(Wrappers.<ColumnModel>lambdaQuery()
                .eq(ColumnModel::getCategoryId, categoryId)
                .isNull(!addGroupId,ColumnModel::getGroupId)
                .eq(addGroupId,ColumnModel::getGroupId,groupId)
                .eq( ColumnModel::getPosition, columnPosition)
                .eq(ColumnModel::getShow, true)
                .orderByAsc(ColumnModel::getSort));
    }

    private void operateColumRe(ColumnModel model) {
        if (model.getConfigs() == null) return;
        reService.delete(reService.wrappers().eq(ExColumnConfigReModel::getColumnId, model.getId()));
        List<ConfigVo> children = model.getConfigs();
        if (CollUtil.isEmpty(children)) return;
        List<ExColumnConfigReModel> add = new LinkedList<>();
        for (ConfigVo child : children) {
            ExColumnConfigReModel m = new ExColumnConfigReModel();
            m.setColumnId(model.getId());
            m.setIsFree(child.getIsFree());
            m.setConfigId(child.getId());
            m.setSort(child.getSort());
            m.setCreatedTime(LocalDateTime.now());
            add.add(m);
        }
        reService.insertBatch(add);
        // 将科目设置成前台可见
        CategoryModel categoryModel = categoryService.getById(model.getCategoryId());
        categoryModel.setShowState(1);
        categoryService.update(categoryModel);
    }

    @PutMapping("/conver-paper")
    @Transactional
    public Boolean convertPaperByChapter(@RequestParam String columnId, PaperType paperType, @RequestParam String sourceYear) {
        this.loadService().update(null, Wrappers.<ColumnModel>lambdaUpdate().set(ColumnModel::getType, ColumnType.paperLibrary).eq(ColumnModel::getId, columnId));
        List<ChapterModel> chapterModels = columnConfigReService.getChaptersByColumn(columnId);
        List<ExColumnConfigReModel> re = new LinkedList<>();
        var allPaper = chapterModels.stream()
                .map(v -> {
                    if (v.getLeaf()) return Collections.singletonList(v);
                    return chapterService.allChildren(v.getId(), -1, chapterService.wrappers().eq(ChapterModel::getLeaf, true)).stream().peek(v1 -> {
                        re.add(ExColumnConfigReModel.builder()
                                .columnId(columnId)
                                .configId(v1.getId())
                                .sort(v1.getSort())
                                .isFree(false)
                                .createdTime(LocalDateTime.now())
                                .build());
                    }).toList();
                })
                .flatMap(List::stream)
                .map(v -> this.convertPaper(v, paperType, sourceYear))
                .toList();
        //删除章节
        List<String> chapterIds = allPaper.parallelStream().map(PaperModel::getId).toList();
        chapterService.delete(chapterIds);
        allPaper.forEach(p -> {
            if (paperService.activation(p) == 0) {
                paperService.insert(p);
            }
        });
        if (!re.isEmpty()) {
            re.forEach(r -> {
                Long aLong = columnConfigReService.selectCount(Wrappers.<ExColumnConfigReModel>lambdaQuery().eq(ExColumnConfigReModel::getColumnId, r.getColumnId()).eq(ExColumnConfigReModel::getConfigId, r.getConfigId()));
                if (aLong == 0) {
                    columnConfigReService.insert(r);
                }
            });
        }
        return true;
    }

    private PaperModel convertPaper(ChapterModel chapterModel, PaperType paperType, String sourceYear) {
        PaperModel paperModel = new PaperModel();
        paperModel.setId(chapterModel.getId());
        paperModel.setName(chapterModel.getName());
        paperModel.setCategoryId(chapterModel.getCategoryId());
        paperModel.setSourceYear(sourceYear);
        paperModel.setPaperType(paperType);
        paperModel.setContentMap(chapterModel.getContentMap());
        paperModel.setQcount(chapterModel.getQcount());
        paperModel.setIntegrityState(0);
        paperModel.setSourceType(2);
        paperModel.setSourceId(chapterModel.getCstkId());
        double sum = chapterModel.getContent().stream().mapToDouble(v -> v.getScore().doubleValue()).sum();
        paperModel.setTotalScore((int) sum);
        paperModel.setPassScore((int) (sum * 0.6));
        paperModel.setSort(chapterModel.getSort());
        return paperModel;
    }

    @PutMapping("/conver-chapter")
    @Transactional
    public Boolean convertChapterByPaper(String columnId) {
        this.loadService().update(null, Wrappers.<ColumnModel>lambdaUpdate().set(ColumnModel::getType, ColumnType.chapterPractice).eq(ColumnModel::getId, columnId));
        List<ExColumnConfigReModel> exColumnConfigReModels = columnConfigReService.selectList(Wrappers.<ExColumnConfigReModel>lambdaQuery().eq(ExColumnConfigReModel::getColumnId, columnId));
        exColumnConfigReModels.forEach(p -> {
            PaperModel paperModel = paperService.getById(p.getConfigId());
            if (paperModel != null) {
                paperService.delete(paperModel.getId());
                ChapterModel chapterModel = new ChapterModel();
                chapterModel.setId(p.getConfigId());
                chapterModel.setQcount(paperModel.getQcount());
                chapterModel.setContent(paperModel.getContent());
                chapterModel.setName(paperModel.getName());
                chapterModel.setCstkId(paperModel.getCstkId());
                chapterModel.setLeaf(true);
                chapterModel.setSort(paperModel.getSort());
                chapterModel.setCategoryId(paperModel.getCategoryId());
                if (chapterService.activation(chapterModel) == 0) {
                    chapterService.insert(chapterModel);
                }
            }
        });
        return true;

    }
    @GetMapping("/columnsByIds")
    public List<ColumnModel> columnsByIds(@RequestParam List<String> ids) {
        List<ColumnModel> column = service.selectBatchIds(ids);
        return column;
    }
    /**
     * 科目试听一节课
     * */
    @GetMapping("/getVideoTrial")
    public VideoInfoModel getVideoTrial(@RequestParam Long categoryId) {
        QueryWrapper<VideoInfoModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("category_id", categoryId);
        List<VideoInfoModel> videoInfoModels = videoInfoMapper.selectList(queryWrapper);
        if(!videoInfoModels.isEmpty()){
            return videoInfoModels.get(0);
        }
        return null;
    }
    @GetMapping("/getVideoTry")
    public List<VideoInfoModel> getVideoTry(@RequestParam String categoryIds) {
        String[] split = categoryIds.split(",");
        Long[] ids  = Arrays.stream(split).map(Long::parseLong).toArray(Long[]::new);
        return videoInfoMapper.getVideoTry(ids);
    }
}
